import Utils from "../../../Utils";
import DestructibleFacility from "../../facility/DestructibleFacility";
import { FacilityType, Gain } from "../../info/GameEnum";
import { Global } from "../../info/Global";
import PlayerManager from "../../manager/PlayerManager";
import UiManager from "../../manager/UiManager";
import AiPlayer from "../AiPlayer";
import Player from "../Player";
import DecisionRoot from "./Decision/DecisionRoot";
import { DecisionTree } from "./DecisionTree";

const { ccclass, property } = cc._decorator;

export type AiEnvironment = {
    player: AiPlayer, //自己
    enemys: Player[],//敌人
    /**
     * 看不见的敌方设施
     */
    invisibilityFacility: DestructibleFacility[],

    /**
     * 看得见的敌方设施
     */
    visibleFacility: DestructibleFacility[],

    /**
     * 看不见，并且攻击过我
     */
    invisibilityAttackedFacility: DestructibleFacility[],

    /**
     * 能看见，并且攻击过我
     */
    visibleAttackedFacility: DestructibleFacility[],

    /**
     * 功能执行可行性
     */
    gainFeasibility: Map<Gain, boolean[]>,

    /**
     * 设施建造可行性
     */
    facilityFeasibility: Map<FacilityType, boolean[]>,

    /**
     * 敌人玩家的总威胁值
     */
    enemyThreatValue: Map<Player, number>,

    /**
     * 敌人玩家的设施威胁值
     */
    enemyFacilityThreatValue: Map<Player, Map<DestructibleFacility, number>>,

    /**
     * 自己的威胁值
     */
    selfThreatValue: number,

    /**
     * 游戏时间
     */
    gameTime: number;
}

@ccclass
export default class AiGameAction extends cc.Component {

    decisionTree: DecisionTree;

    aiPlayer: AiPlayer;

    waitTime: number;

    init(player: AiPlayer) {
        this.aiPlayer = player;
        this.waitTime = 0;
    }

    /**
     * 重复执行 执行完随机一段时间后再次执行
     */
    run() {
        let time = Utils.getRandom(5, 50) / 10;
        if (Global.chooseMode == 1) {
            time = time * 0.7;
        }
        this.scheduleOnce(() => {
            this.runDecisiionTree();
            this.run();
        }, time)
    }


    private runDecisiionTree() {
        let enemys: Player[] = this.getEmemys();

        //看不见的设施
        let invisibilityFacility = []
        //看得见的设施
        let visibleFacility: DestructibleFacility[] = []
        //攻击过我，并且看不见的设施
        let invisibilityAttackedFacility: DestructibleFacility[] = []
        //攻击过我，并且看得见的设施
        let visibleAttackedFacility: DestructibleFacility[] = []
        //敌人对应的威胁值，距离越近威胁越大
        let enemyThreatValue = new Map<Player, number>();
        //敌人设施的威胁值
        let enemyFacilityThreatValue = new Map<Player, Map<DestructibleFacility, number>>();
        //自身威胁值
        let selfThreatValue = 0;

        enemys.forEach(enemy => {
            let threatValueTotal = 0;
            let facilityThreatValueMap = new Map<DestructibleFacility, number>();
            enemy.allFacility.forEach(facility => {
                let hurtMyFac = this.aiPlayer.facilityHurtMyFacility.has(facility);
                let hurtMyFlyer = this.aiPlayer.facilityHurtMyFlyer.has(facility);
                let isVisible = this.aiPlayer.isFacilityVisible(facility);
                if (isVisible) {
                    visibleFacility.push(facility);
                    if (hurtMyFac || hurtMyFlyer) {
                        visibleAttackedFacility.push(facility);
                    }
                } else {
                    invisibilityFacility.push(facility);
                    if (hurtMyFac || hurtMyFlyer) {
                        invisibilityAttackedFacility.push(facility);
                    }
                }
                let threatValue = this.getFacilityThreatValueForMe(facility);
                if (threatValue) {
                    facilityThreatValueMap.set(facility, threatValue);
                    threatValueTotal += threatValue;
                }
            });
            if (threatValueTotal) {
                enemyThreatValue.set(enemy, threatValueTotal);
                enemyFacilityThreatValue.set(enemy, facilityThreatValueMap);
            };
        });

        this.aiPlayer.allFacility.forEach(item => selfThreatValue += item.threatValue);

        let environment: AiEnvironment = {
            player: this.aiPlayer,
            enemys: enemys,
            invisibilityFacility: invisibilityFacility,
            visibleFacility: visibleFacility,
            visibleAttackedFacility: visibleAttackedFacility,
            invisibilityAttackedFacility: invisibilityAttackedFacility,
            gainFeasibility: this.getGainDecisionFeasibility(),
            facilityFeasibility: this.getFacilityDecisionFeasibility(),
            enemyThreatValue: enemyThreatValue,
            enemyFacilityThreatValue: enemyFacilityThreatValue,
            selfThreatValue: selfThreatValue,
            gameTime: UiManager.instance.gameTime
        }

        this.decisionTree = new DecisionTree(new DecisionRoot(environment));
        this.waitTime = this.decisionTree.decide();
    }

    /**
     * 获取设施对我的威胁值(计算距离)
     * @param facility 
     * @returns 
     */
    getFacilityThreatValueForMe(facility: DestructibleFacility) {
        let result = 0;
        //看得见
        if (this.aiPlayer.isFacilityVisible(facility)) {
            let mainhomeLocation = this.aiPlayer.facilityArr[FacilityType.主基地][0].locations[0];
            let otherLocation = facility.locations[0];
            let disX = Math.abs(mainhomeLocation.locationX - otherLocation.locationX),
                disY = Math.abs(mainhomeLocation.locationY - otherLocation.locationY)
            let distance = Math.sqrt(disX * disX + disY * disY);
            result = Math.ceil(facility.threatValue + distance);

            //攻击过我设施 威胁值翻1.5倍
            if (this.aiPlayer.facilityHurtMyFacility.has(facility)) {
                result = Math.ceil(result * 1.5);
            }
            //攻击过我飞行物 威胁值翻1.2倍
            if (this.aiPlayer.facilityHurtMyFlyer.has(facility)) {
                result = Math.ceil(result * 1.2);
            }
        } else {
            //看不见但是攻击过我
            let hurtMyFac = this.aiPlayer.facilityHurtMyFacility.has(facility),
                hurtMyFlyer = this.aiPlayer.facilityHurtMyFlyer.has(facility);
            if (hurtMyFac || hurtMyFlyer) {
                result = facility.threatValue;
                if (hurtMyFac) {
                    result = Math.ceil(result * 1.5);
                }
                if (hurtMyFlyer) {
                    result = Math.ceil(result * 1.2);
                }
            }
        }
        return result;
    }

    /**
     * 获取所有生存的敌人
     * @returns 
     */
    private getEmemys(): Player[] {
        let enemys: Player[] = [];
        PlayerManager.instance.playerParent.children.forEach(item => {
            if (item.active) {
                let player = item.getComponent(Player);
                if (player != this.aiPlayer && player.facilityArr[FacilityType.主基地].length) {
                    enemys.push(player);
                }
            }
        });
        return enemys;
    }


    /**
     * 获取所有功能的执行可行性
     * @returns 
     */
    private getGainDecisionFeasibility(): Map<Gain, boolean[]> {
        let result: Map<Gain, boolean[]> = new Map<Gain, boolean[]>();
        //已解锁 未满足晶矿和油矿条件
        result.set(Gain.招募矿工, this.aiPlayer.checkGainCondition(Gain.招募矿工));
        result.set(Gain.升级主基地, this.aiPlayer.checkGainCondition(Gain.升级主基地));
        result.set(Gain.建筑血量升级, this.aiPlayer.checkGainCondition(Gain.建筑血量升级));
        result.set(Gain.建筑防御升级, this.aiPlayer.checkGainCondition(Gain.建筑防御升级));
        result.set(Gain.炮弹射程升级, this.aiPlayer.checkGainCondition(Gain.炮弹射程升级));
        result.set(Gain.炮弹攻击力升级, this.aiPlayer.checkGainCondition(Gain.炮弹攻击力升级));
        result.set(Gain.炮弹血量升级, this.aiPlayer.checkGainCondition(Gain.炮弹血量升级));
        result.set(Gain.维修基地, this.aiPlayer.checkGainCondition(Gain.维修基地));
        result.set(Gain.近防炮攻击升级, this.aiPlayer.checkGainCondition(Gain.近防炮攻击升级));
        result.set(Gain.采矿数量升级, this.aiPlayer.checkGainCondition(Gain.采矿数量升级));
        result.set(Gain.采矿速度升级, this.aiPlayer.checkGainCondition(Gain.采矿速度升级));
        return result;
    }

    /**
     * 获取所有设施的建造可行性
     * @returns 
     */
    private getFacilityDecisionFeasibility(): Map<FacilityType, boolean[]> {
        let result: Map<FacilityType, boolean[]> = new Map<FacilityType, boolean[]>();
        result.set(FacilityType.矿机, this.aiPlayer.checkFacilityCondition(FacilityType.矿机));
        result.set(FacilityType.采油机, this.aiPlayer.checkFacilityCondition(FacilityType.采油机));
        result.set(FacilityType.领土扩张器, this.aiPlayer.checkFacilityCondition(FacilityType.领土扩张器));
        result.set(FacilityType.近防炮, this.aiPlayer.checkFacilityCondition(FacilityType.近防炮));
        result.set(FacilityType.榴弹炮基地, this.aiPlayer.checkFacilityCondition(FacilityType.榴弹炮基地));
        result.set(FacilityType.火箭炮基地, this.aiPlayer.checkFacilityCondition(FacilityType.火箭炮基地));
        result.set(FacilityType.电磁炮基地, this.aiPlayer.checkFacilityCondition(FacilityType.电磁炮基地));
        result.set(FacilityType.洲际导弹基地, this.aiPlayer.checkFacilityCondition(FacilityType.洲际导弹基地));
        result.set(FacilityType.核弹基地, this.aiPlayer.checkFacilityCondition(FacilityType.核弹基地));
        result.set(FacilityType.照明弹基地, this.aiPlayer.checkFacilityCondition(FacilityType.照明弹基地));
        result.set(FacilityType.侦察机基地, this.aiPlayer.checkFacilityCondition(FacilityType.侦察机基地));
        return result;
    }

    clear() {
        this.unscheduleAllCallbacks();
    }
}
